package kik.client.chat;

import java.util.ArrayList;

import kik.client.Conference;
import kik.client.common.ConferenceObject;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

/**
 * Klasa definiująca tworzenie chatu.
 * Definiuje on wygląd graficzny chatu oraz zajmuje się obsługą zdarzeń wykonanych na obiekcie chat
 */
public class Chat extends ConferenceObject {
	private DockPanel layout = new DockPanel();
	private HorizontalPanel input = new HorizontalPanel();
	private TextBox input_text = new TextBox();
	private HTML userList = new HTML();
	private Button send_button = new Button();
	private ScrollPanel contacts;
	private HTML chat = new HTML();
	private ArrayList<String> chat_log = new ArrayList<String>();
	private ScrollPanel scroll;
	private String local_name = "Me";
	
	/**
	 * Konstruktor tworzący nowy obiekt chatu.
	 * 
	 * Tworzy elementy graficzne oraz układa je w odpowiedniej hierarchii.
	 * Definiuje także obsługe zdarzeń wykonanych na elementach graficznych.
	 * @param c Obiekt konferencji (@link Conference}
	 */
	public Chat(Conference c) {
		conf = c;
		owner = "";
		scroll = new ScrollPanel(chat);
		contacts = new ScrollPanel(userList);
		// wiadomosc zostaje po nacisnieciu przycisku 'enter'
		input_text.addKeyPressHandler(new KeyPressHandler() {
										public void onKeyPress(KeyPressEvent event) {
											if(event.getCharCode() == '\r' ||
													event.getCharCode() == '\n') {
												processSend();
											}
										}
		});
		input.add(input_text);
		send_button.setText("Send");
		// guzik do wysylania wiadomosci
		send_button.addClickHandler(new ClickHandler() {
											public void onClick(ClickEvent event) {
												processSend();
											}
										}
		);
		input.add(send_button);
		DecoratorPanel tmp = new DecoratorPanel();
		DecoratorPanel tmp2 = new DecoratorPanel();
		
		chat.setWidth("200px");
		userList.setWidth("200px");
		scroll.setHeight("250px");
		contacts.setHeight("200px");
		tmp.add(scroll);
		tmp2.add(contacts);
		layout.setSpacing(5);
		layout.add(tmp2, DockPanel.NORTH);
		layout.add(input, DockPanel.SOUTH);
		layout.add(tmp, DockPanel.SOUTH);
		
		// inicjowanie widget`u
		initWidget(layout);
	}
	
	/**
	 * Funkcja dodjąca nową linijke do historii chatu.
	 * @param from	Nazwa nadawcy wiadomości.
	 * @param what	Treść wiadomości.
	 */
	public void addChatLineToLog(String from, String what) {
		chat_log.add(from+"~~~"+what);
	}
	
	/**
	 * Funkcja przetwarzająca wysyłanie nowej wiadomości dodanej przez użytkownika.
	 * Dodaje wiadomość do historii chatu.
	 * Dodaje do okna chatu użytkownika oraz wysyła do reszty konferencji.
	 */
	private void processSend() {
		String in = input_text.getValue();
		if(in != "") {
			addChatLineToLog(owner,in);
			chat.setHTML(chat.getHTML() + 
					formatChatLine(local_name,in));
			sendMsg(in);
		}
		input_text.setValue("");
		input_text.setFocus(true);
		if(chat.getOffsetHeight() >= scroll.getOffsetHeight())
			scroll.scrollToBottom();
	}
	
	/**
	 * Funkcja formatująca. Skleja nazwę właściciela wiadomości oraz treść wiadomości,
	 * tak aby można było wyświetlić to w oknie HTML użytkownika.
	 * @param owner	Właściciel wiadomośći.
	 * @param what	Treść wiadomości
	 * @return
	 */
	public String formatChatLine(String owner, String what) {
		return "<b>"+owner+":</b> " + what + "<br>\n";
	}
	
	/**
	 * Zwraca obiekt UI z ułożonymi elementami chatu.
	 * @return	Obiekt z ułożonymi elementami chatu.
	 */
	public Widget getLayout() {
		return layout;
	}
	
	/**
	 * Wsyła nową wiadomość do reszty konferencji.
	 * @param msg	Treść wiadomości.
	 */
	public void sendMsg(String msg) {
		conf.send(new ChatChange(conf.getConferenceId(),msg));
	}

	/**
	 * Funkcja obsługująca nadejście zmiany chatu (obsługa zdarzenia przyjścia wiadomości do konferencji).
	 * @param change	Obiekt zmiany chatu.
	 */
	public void handleChatChange(ChatChange change) {
		String msg = change.getTextChange();
		String user = change.getFromUser();
		if(msg.startsWith("~~~")) {
			String lines[] = msg.split("~~~");
			if(lines.length > 2) {
				user = lines[1];
				msg = lines[2];
			}
		}
		addChatLineToLog(user, msg);
		chat.setHTML(chat.getHTML() + formatChatLine(user, msg));
		if(chat.getOffsetHeight() >= scroll.getOffsetHeight())
			scroll.scrollToBottom();
	}
	
	/**
	 * Funkcja odświeżająca okno listy kontatków.
	 */
	public void refreshContacts() {
		ArrayList<String> members = conf.getMembers();
		String t = "";
		for(int i = 0; i < members.size(); ++i) {
			t += "<b>"+members.get(i)+"</b><br>\n";
		}
		userList.setHTML(t);
	}
	
	/**
	 * Funkcja ustawiająca właściciela chatu.
	 * @param o	Właściciel chatu.
	 */
	public void setOwner(String o) {
		owner = o;
	}
	
	/**
	 * Synchronizowanie chatu z nowym członkiem konferencji.
	 * @param newMember	Nazwa nowego członka.
	 */
	public void syncWith(String newMember) {
		for(int i = 0; i < chat_log.size(); ++i) {
			conf.sendTo(newMember, new ChatChange(conf.getConferenceId(),"~~~"+chat_log.get(i)));
		}
	}
}